<template>
  <div class="anomaly-chart-container">
    <div class="chart-header">
      <h3>异常分数曲线</h3>
      <button class="refresh-btn" @click="refreshChart">实时更新</button>
    </div>
    <div class="chart-wrapper">
      <div v-if="loadError" class="chart-error">
        <p>图表加载失败: {{ loadError }}</p>
        <button @click="retryLoadChart">重试</button>
      </div>
      <div v-else-if="!chartLoaded" class="chart-loading">
        <p>正在加载图表...</p>
      </div>
      <canvas v-show="chartLoaded" ref="chartCanvas" width="800" height="400"></canvas>
    </div>
  </div>
</template>

<script>
import { ref, onMounted, onUnmounted, watch } from 'vue';

export default {
  name: 'AnomalyChart',
  props: {
    // 异常分数数据
    anomalyScores: {
      type: Array,
      default: () => []
    },
    // 阈值
    threshold: {
      type: Number,
      default: 60
    },
    // 当前播放帧
    currentFrame: {
      type: Number,
      default: 0
    }
  },
  emits: ['refresh'],
  setup(props, { emit }) {
    const chartCanvas = ref(null);
    let chartInstance = null;
    const chartLoaded = ref(false);
    const loadError = ref('');

    // 调试信息
    console.log('AnomalyChart组件初始化，props:', {
      anomalyScores: props.anomalyScores,
      anomalyScoresLength: props.anomalyScores.length,
      threshold: props.threshold
    });

    // 生成时间标签，基于实时播放的关键帧
    const generateTimeLabels = (count) => {
      const labels = [];
      const frameRate = 25; // 假设帧率为25fps
      
      // 如果当前播放帧为0，只生成第0帧的标签
      if (props.currentFrame === 0) {
        return ['00:00'];
      }
      
      // 生成时间格式标签，基于实时播放的关键帧
      for (let i = 0; i < count; i++) {
        const frameNum = i + 1;
        
        // 计算时间（秒）
        const seconds = frameNum / frameRate;
        // 格式化为 mm:ss 格式
        const mins = Math.floor(seconds / 60);
        const secs = Math.floor(seconds % 60);
        const timeLabel = `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
        
        // 只显示当前播放帧范围内的关键时间点
        if (frameNum <= props.currentFrame) {
          // 优化标签显示：每隔一段时间显示一个标签，避免标签过于密集
          if (frameNum === 1 || frameNum === props.currentFrame || frameNum % Math.ceil(props.currentFrame / 10) === 0) {
            labels.push(timeLabel);
          } else {
            labels.push('');
          }
        } else {
          labels.push('');
        }
      }
      
      return labels;
    };

    // 初始化图表
    const initChart = () => {
      try {
        // 检查canvas元素是否存在
        if (!chartCanvas.value) {
          console.warn('图表画布元素不存在');
          return;
        }

        // 检查Chart.js是否已加载
        if (!window.Chart) {
          console.error('Chart.js未加载，无法初始化图表');
          loadError.value = '图表库加载失败';
          return;
        }

        const ctx = chartCanvas.value.getContext('2d');
        const dataLength = props.anomalyScores && props.anomalyScores.length > 0 ? props.anomalyScores.length : 1;
        const labels = generateTimeLabels(dataLength);
        
        // 准备数据集
        const anomalyData = props.anomalyScores && props.anomalyScores.length > 0 ? 
          [...props.anomalyScores] : [0];
        const thresholdData = Array(dataLength).fill(props.threshold);

        // 销毁已存在的图表实例，避免内存泄漏
        if (chartInstance instanceof window.Chart) {
          chartInstance.destroy();
          chartInstance = null;
        }

        // 创建新的图表实例
        chartInstance = new window.Chart(ctx, {
          type: 'line',
          data: {
            labels: labels,
            datasets: [
              {
                label: '异常分数 (%)',
                data: anomalyData,
                borderColor: '#1890ff',
                backgroundColor: 'rgba(24, 144, 255, 0.1)',
                borderWidth: 2,
                pointRadius: 3,
                pointHoverRadius: 3,
                tension: 0.1,
                fill: true,
                pointBackgroundColor: '#1890ff',
                pointBorderColor: '#1890ff',
                pointBorderWidth: 1,
                spanGaps: false
              },
              {
                label: `阈值 ${props.threshold}%`,
                data: thresholdData,
                borderColor: '#ff4d4f',
                backgroundColor: 'transparent',
                borderWidth: 2,
                borderDash: [5, 5],
                pointRadius: 0,
                pointHoverRadius: 0,
                pointStyle: false,
                fill: false,
                spanGaps: false
              }
            ]
          },
          options: {
            responsive: true,
            maintainAspectRatio: false,
            animation: {
              duration: 0
            },
            scales: {
              y: {
                beginAtZero: true,
                max: 100,
                ticks: {
                  stepSize: 10
                },
                title: {
                  display: true,
                  text: '转化后分数 (%)'
                }
              },
              x: {
                display: true,
                title: {
                  display: true,
                  text: '时间'
                },
                ticks: {
                  maxRotation: 0,
                  minRotation: 0,
                  autoSkip: true,
                  padding: 10
                },
                grid: {
                  display: false
                }
              }
            },
            plugins: {
              legend: {
                display: false
              },
              tooltip: {
                mode: 'index',
                intersect: false,
                callbacks: {
                  label: function(context) {
                    if (context.datasetIndex === 1) {
                      return `阈值: ${props.threshold}%`;
                    }
                    return `异常分数: ${context.parsed.y}%`;
                  }
                }
              }
            },
            interaction: {
              mode: 'nearest',
              axis: 'x',
              intersect: false
            }
          }
        });
      } catch (error) {
        console.error('初始化图表失败:', error);
        loadError.value = '图表初始化失败';
      }
    };

    // 用于跟踪上一次更新的异常数据和帧位置
    let lastAnomalyScores = [];
    let lastCurrentFrame = 0;
    let maxDataFrameIndex = -1; // 记录有有效数据的最大帧索引
    let forceUpdateFlag = false; // 强制更新标志

    // 更新图表数据
    const updateChart = () => {
        if (!chartInstance) return;

        // 首先确定有有效异常数据的最大帧索引
        let currentMaxDataFrameIndex = -1;
        for (let i = 0; i < props.anomalyScores.length; i++) {
          // 假设非零、非null且非undefined的值为有效数据点
          if (props.anomalyScores[i] !== 0 && props.anomalyScores[i] !== null && props.anomalyScores[i] !== undefined) {
            currentMaxDataFrameIndex = i;
          }
        }

        // 如果是首次运行，初始化maxDataFrameIndex
        if (maxDataFrameIndex === -1) {
          maxDataFrameIndex = currentMaxDataFrameIndex;
        }

        // 核心优化逻辑：如果当前播放帧超过了有有效数据的最大帧索引，并且没有新的数据点出现，不更新图表
        const hasNewDataPoints = currentMaxDataFrameIndex > maxDataFrameIndex;
        const frameExceedsDataRange = props.currentFrame > maxDataFrameIndex && !hasNewDataPoints;
        
        // 只在以下情况更新图表：
        // 1. 有新的数据点出现
        // 2. 播放帧在有效数据范围内变化
        // 3. 强制更新标志为true（用于数据清空时）
        if (frameExceedsDataRange && !forceUpdateFlag) {
          return; // 播放到没有新异常数据的区域，不更新图表
        }
        
        // 重置强制更新标志
        forceUpdateFlag = false;

        // 更新最大数据帧索引（如果有新数据点）
        if (hasNewDataPoints) {
          maxDataFrameIndex = currentMaxDataFrameIndex;
        }

        // 检查帧位置是否变化
        const frameChanged = props.currentFrame !== lastCurrentFrame;

        // 根据当前播放帧生成适合的数据和标签数组，确保从左到右撑满x轴
        const displayLength = Math.max(props.currentFrame + 1, 1); // 至少显示1帧
        let displayScores = [];
        let displayLabels = [];
        
        // 初始化数组，确保长度足够
        for (let i = 0; i < displayLength; i++) {
          if (i < props.anomalyScores.length) {
            displayScores.push(props.anomalyScores[i]);
          } else {
            displayScores.push(null);
          }
          displayLabels.push('');
        }
        
        // 生成时间标签，基于实时播放的关键帧
        const frameRate = 25;
        for (let i = 0; i < displayLength; i++) {
          const frameNum = i + 1;
          
          // 只在关键时间点显示标签
          if (frameNum === 1 || frameNum === displayLength || frameNum % Math.ceil(displayLength / 10) === 0) {
            const seconds = frameNum / frameRate;
            const mins = Math.floor(seconds / 60);
            const secs = Math.floor(seconds % 60);
            displayLabels[i] = `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
          }
        }
        
        // 特殊处理：如果是第0帧，只显示00:00标签
        if (props.currentFrame === 0) {
          displayLabels = ['00:00'];
          displayScores = props.anomalyScores.length > 0 ? [props.anomalyScores[0] || 0] : [0];
        }
        
        // 只有在帧位置变化或有新数据点时才更新图表
        if (frameChanged || hasNewDataPoints) {
          // 更新图表数据
          chartInstance.data.labels = displayLabels;
          chartInstance.data.datasets[0].data = displayScores;
          
          // 确保点样式保持一致，避免点大小不一致的问题
          chartInstance.data.datasets[0].pointRadius = 3;     // 固定点大小为3
          chartInstance.data.datasets[0].pointHoverRadius = 3; // 悬停时也保持相同大小
          chartInstance.data.datasets[0].pointBackgroundColor = 'rgb(75, 192, 192)';
          chartInstance.data.datasets[0].pointBorderColor = 'rgb(75, 192, 192)';
          chartInstance.data.datasets[0].pointBorderWidth = 1;
          
          // 更新阈值线数据，确保长度匹配
          chartInstance.data.datasets[1].data = Array(displayLength).fill(props.threshold);
          chartInstance.data.datasets[1].label = `阈值 ${props.threshold}%`;
          
          // 更新跟踪信息
          lastAnomalyScores = [...props.anomalyScores];
          lastCurrentFrame = props.currentFrame;
          
          // 使用默认更新模式以启用从右方滑入的动画效果
          chartInstance.update();
        }
    };

    // 刷新图表
    const refreshChart = () => {
      emit('refresh');
    };

    // 动态加载Chart.js
    const loadChartJs = async () => {
      if (window.Chart) {
        chartLoaded.value = true;
        initChart();
        return;
      }
      
      try {
        // 创建script标签加载Chart.js
        const chartScript = document.createElement('script');
        chartScript.src = 'https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js';
        chartScript.async = false;
        
        await new Promise((resolve, reject) => {
          chartScript.onload = resolve;
          chartScript.onerror = () => reject(new Error('Chart.js加载失败'));
          document.head.appendChild(chartScript);
        });
        
        // 等待Chart.js加载完成
        await new Promise(resolve => setTimeout(resolve, 200));
        
        if (window.Chart) {
          chartLoaded.value = true;
          initChart();
        } else {
          throw new Error('Chart.js未正确加载');
        }
        
      } catch (error) {
        console.error('Chart.js加载失败:', error);
        loadError.value = error.message;
      }
    };
    
    // 重试加载
    const retryLoadChart = () => {
      loadError.value = '';
      chartLoaded.value = false;
      loadChartJs();
    };

    onMounted(() => {
      loadChartJs();
    });

    onUnmounted(() => {
      if (chartInstance) {
        chartInstance.destroy();
      }
    });

    // 监听数据变化
    watch(() => props.anomalyScores, (newScores) => {
      console.log('异常分数数据变化:', {
        oldLength: props.anomalyScores.length,
        newLength: newScores.length,
        newScores: newScores
      });
      
      // 如果新数据为空数组，强制更新图表
      if (newScores.length === 0) {
        forceUpdateFlag = true;
        // 重置相关跟踪变量
        maxDataFrameIndex = -1;
        lastAnomalyScores = [];
        lastCurrentFrame = 0;
      }
      
      if (chartInstance) {
        updateChart();
      }
    }, { deep: true });
    
    // 监听当前播放帧变化
    watch(() => props.currentFrame, (newFrame) => {
      console.log('当前播放帧变化:', newFrame);
      if (chartInstance) {
        updateChart();
      }
    });

    watch(() => props.threshold, (newThreshold) => {
      if (chartInstance) {
        // 更新阈值线数据集
        chartInstance.data.datasets[1].data = props.anomalyScores.length > 0 ? 
          Array(props.anomalyScores.length).fill(newThreshold) : [newThreshold];
        chartInstance.data.datasets[1].label = `阈值 ${newThreshold}%`;
        chartInstance.update();
      }
    });

    return {
      chartCanvas,
      refreshChart,
      chartLoaded,
      loadError,
      retryLoadChart
    };
  }
};
</script>

<style scoped>
.anomaly-chart-container {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
  background-color: #fff;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.chart-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}

.chart-header h3 {
  margin: 0;
  font-size: 18px;
  font-weight: 600;
  color: #333;
}

.refresh-btn {
  padding: 8px 16px;
  background-color: #007bff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  transition: background-color 0.3s;
}

.refresh-btn:hover {
  background-color: #0056b3;
}

.chart-wrapper {
  position: relative;
  height: 400px;
  width: 100%;
  overflow: hidden;
}

.chart-container canvas {
  animation: slideFromRight 0.5s ease-out forwards;
}

@keyframes slideFromRight {
  from {
    transform: translateX(100%);
    opacity: 0;
  }
  to {
    transform: translateX(0);
    opacity: 1;
  }
}

.chart-loading {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: #666;
  font-size: 16px;
}

.chart-error {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: #dc3545;
  font-size: 16px;
  text-align: center;
}

.chart-error button {
  margin-top: 10px;
  padding: 8px 16px;
  background-color: #dc3545;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
}

.chart-error button:hover {
  background-color: #c82333;
}

@media (max-width: 768px) {
  .anomaly-chart-container {
    padding: 10px;
  }
  
  .chart-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
  }
  
  .chart-wrapper {
    height: 300px;
  }
}
</style>